package com.axonactive.yolo.controller;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.meta.Exhaustive;
import javax.mail.MessagingException;
import javax.servlet.http.HttpSession;

import org.apache.http.client.ClientProtocolException;
import org.apache.log4j.Logger;
import org.atmosphere.cpr.BroadcasterFactory;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.axonactive.yolo.domain.FlightNotification;
import com.axonactive.yolo.domain.SubscribedFlight;
import com.axonactive.yolo.domain.Task;
import com.axonactive.yolo.domain.TaskNotification;
import com.axonactive.yolo.domain.TaskUserId;
import com.axonactive.yolo.domain.User;
import com.axonactive.yolo.domain.UserEmail;
import com.axonactive.yolo.dto.Email;
import com.axonactive.yolo.dto.Flight;
import com.axonactive.yolo.dto.FlightNotificationDTO;
import com.axonactive.yolo.dto.JsonData;
import com.axonactive.yolo.dto.TaskAlert;
import com.axonactive.yolo.dto.TaskNotificationDTO;
import com.axonactive.yolo.dtotemp.WegoFlight;
import com.axonactive.yolo.monitor.CheckUpdateCurrency;
import com.axonactive.yolo.monitor.ServiceProvider;
import com.axonactive.yolo.notification.FlightNotifier;
import com.axonactive.yolo.service.api.TravelPayoutsAPI;
import com.axonactive.yolo.service.api.WegoAPI;
import com.axonactive.yolo.service.automatic.search.TaskPrepartion;
import com.axonactive.yolo.service.interfaces.CountryService;
import com.axonactive.yolo.service.interfaces.EmailService;
import com.axonactive.yolo.service.interfaces.ExchangeRateService;
import com.axonactive.yolo.service.interfaces.FlightNotificationService;
import com.axonactive.yolo.service.interfaces.TaskService;
import com.axonactive.yolo.service.interfaces.TaskUserIdService;
import com.axonactive.yolo.service.interfaces.UserEmailService;
import com.axonactive.yolo.service.interfaces.UserService;
import com.axonactive.yolo.service.internal.FlightRequester;
import com.axonactive.yolo.service.internal.JsonDataService;
import com.axonactive.yolo.service.internal.TaskNotificationService;
import com.axonactive.yolo.util.CONSTANTS;
import com.axonactive.yolo.util.EncryptDecrypt;
import com.axonactive.yolo.util.IOUtil;
import com.axonactive.yolo.util.session.SessionHelper;

@Controller
@RequestMapping(value = "/demo")
public class DemoController {

	@Autowired
	private JsonDataService jsonDataService;

	@Autowired
	private FlightNotificationService flightNotificationService;

	@Autowired
	private CountryService countryService;
	
	@Autowired
	private TaskService taskService;
	
	@Autowired
	private TaskUserIdService taskUserIdService;
	
	@Autowired
	private EmailService emailService;
	
	@Autowired
	private UserEmailService userEmailService;
	
	@Autowired
	private ExchangeRateService exchangeRateService;
	
	@Autowired
	private UserService userService;
	
	@Autowired
	private TaskNotificationService taskNotificationService;
	
	private static final Logger LOGGER = Logger.getLogger(DemoController.class);

	private static final String DEMO_ECNCRYPTION = "demo/encryption";
	private static final String DEMO_AIRLINE = "demo/airline";
	private static final String DEMO_MULTISLIDER = "demo/multislider";
	private static final String FLIGHT_MODELS = "fligths";


	@RequestMapping(value = { "/demo" }, method = RequestMethod.GET)
	public ModelAndView index() {
		return new ModelAndView("demo/demo");
	}

	@RequestMapping(value = { "/how_api" }, method = RequestMethod.GET)
	public ModelAndView getDataFromAPI(Map<String, Object> model) {
		FlightRequester pullData = new WegoAPI();
		String response;
		try {
			// You can set "" for the uncared field
			pullData.setRequest("HAN", "SGN", "roundTrip", "Economy",
					"2014-03-28", "2014-03-25", "1", "0", "", "", "USD");
			response = pullData.sendRequest();
			List<WegoFlight> flights = pullData
					.processResponseWego(response);
			if (flights == null) {
				return new ModelAndView("demo/how_api", "msg",
						"The key is invalid or exceeded.");
			}
			model.put(FLIGHT_MODELS, flights);
		} catch (Exception e) {
			LOGGER.info("Cant get Data from API: ", e);
		}
		return new ModelAndView("demo/how_api");
	}

	@RequestMapping(value = { "/encryption" }, method = RequestMethod.GET)
	public ModelAndView encryptData() {
		return new ModelAndView(DEMO_ECNCRYPTION);
	}

	/*
	 * Airline filter
	 */
	@RequestMapping(value = { "/airline_filter" }, method = RequestMethod.GET)
	public ModelAndView auto() {
		return new ModelAndView(DEMO_AIRLINE);
	}

	@RequestMapping(value = { "/airline_filter" }, method = RequestMethod.POST)
	public ModelAndView showResultAuto(
			@RequestParam(value = "airlines", required = false) String airlines) {

		return new ModelAndView(DEMO_AIRLINE, "message", airlines);
	}

	@RequestMapping(value = { "/encryption" }, method = RequestMethod.POST)
	public ModelAndView showEncryptData(
			@RequestParam(value = "inputString", required = false) String input,
			Map<String, Object> model) {
		try {
			String encrypted = EncryptDecrypt.encryptDES(input);
			String decrypted = EncryptDecrypt.decryptDES(encrypted);
			model.put("input", "Inputed String: " + input);
			model.put("encripted_data", "Encrypted String: " + encrypted);
			model.put("decripted_data", "Decrypted String: " + decrypted);
		} catch (Exception ex) {
			LOGGER.info("Can't Encrypt and Decrypt",ex) ;
		}
		return new ModelAndView(DEMO_ECNCRYPTION);
	}

	@RequestMapping(value = { "/kayak" }, method = RequestMethod.GET)
	public ModelAndView getDataFromKayak() throws IOException {
		List<String> result = IOUtil.executeProgram(CONSTANTS.KAYAK);
		return new ModelAndView("demo/grap_data_kayak", "result", result);

	}

	@RequestMapping(value = { "/skyscanner" }, method = RequestMethod.GET)
	public ModelAndView getDataFromSky() throws IOException {
		List<String> result = IOUtil.executeProgram(CONSTANTS.SKYSCANNER);
		return new ModelAndView("demo/grap_data_skyscanner", "result", result);
	}

	@RequestMapping(value = { "/tripadvisor" }, method = RequestMethod.GET)
	public ModelAndView getDataFromTrip() throws Exception {
		List<String> result = IOUtil.executeProgram(CONSTANTS.TRIPADVISOR);
		return new ModelAndView("demo/grap_data_tripadvisor", "result", result);
	}

	@RequestMapping(value = { "/travelpayouts" }, method = RequestMethod.GET)
	public ModelAndView travelpayouts(Map<String, Object> model) {
		String response = "";

		TravelPayoutsAPI travelPayoutsAPI = new TravelPayoutsAPI();
		travelPayoutsAPI.setRequest("HAN", "SGN", "", "Economy", "2014-03-20",
				"2014-03-15", "1", "0", "0", "0", "USD");
		response = travelPayoutsAPI.sendRequest();
		List<Flight> flights = travelPayoutsAPI.processResponse(response);

		model.put("flights", flights);

		return new ModelAndView("demo/travelpayouts");
	}

	@RequestMapping(value = { "/slider" }, method = RequestMethod.GET)
	public ModelAndView simpleModule(Map<String, Object> model) {

		return new ModelAndView("demo/slider");

	}

	@RequestMapping(value = { "/slider" }, method = RequestMethod.POST)
	public ModelAndView getNumberOfStops(
			@RequestParam(value = "numStops", required = true) String numStops,
			Map<String, Object> model) {
		Logger.getLogger(DemoController.class).info(
				"Number of stops: " + numStops);
		return new ModelAndView("demo/slider", "stops", numStops);

	}

	@RequestMapping(value = { "/multislider" }, method = RequestMethod.GET)
	public ModelAndView sliderWithMultiHandle() {
		return new ModelAndView(DEMO_MULTISLIDER);

	}

	@RequestMapping(value = { "/multislider" }, method = RequestMethod.POST)
	public ModelAndView sliderWithMultiHandle(
			@RequestParam(value = "time", required = true) String time,
			Map<String, Object> model) {
		Logger.getLogger(DemoController.class).info("Time: " + time);
		return new ModelAndView(DEMO_MULTISLIDER);

	}

	// For atmostphere demo
	@RequestMapping(method = RequestMethod.GET, value = "/atmostphere1")
	public String atmostphereDemo1(HttpSession session) {
		String testingNotification = null;
		FlightNotification flightNotification = new FlightNotification();
		flightNotification.setUserId(SessionHelper.getUserId(session));
		flightNotification.setFlightId("TESTINGFLIGHTID");
		flightNotification.setFlightRoute("DAD-SGN");
		flightNotification.setFlightDepartureTime("2014/03/27 21:45");
		flightNotification.setOldPrice(58);
		flightNotification.setNewPrice(60);
		flightNotification.setCurrencyCode("USD");
		flightNotification.setFlightChangeType(0);
		flightNotification.setStatus(0);
		flightNotification.setIsRead(0);
		DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date date = new Date();
		flightNotification.setSaveTime(dateFormat.format(date));
		flightNotificationService.create(flightNotification);

		FlightNotificationDTO flightNotificationDTO = new FlightNotificationDTO(flightNotification);
		List<FlightNotificationDTO> flightNotificationDTOs = new ArrayList<>();
		flightNotificationDTOs.add(flightNotificationDTO);
		try {
			ObjectMapper makeJson = new ObjectMapper();
			testingNotification = makeJson.writeValueAsString(flightNotificationDTOs);
		} catch (Exception e) {
			LOGGER.error("Error when make Json",e);
		}
		
		LOGGER.info("Notification: " + testingNotification);
		BroadcasterFactory.getDefault().lookup(SessionHelper.getUserId(session)).broadcast("10"+testingNotification);
		return "demo/atmostphere";
	}
	
	// For atmostphere demo
		@RequestMapping(method = RequestMethod.GET, value = "/atmostphere2")
		public String atmostphereDemo2(HttpSession session) throws JsonGenerationException, JsonMappingException, IOException {
			String testingNotification = null;
			TaskNotification taskNotification = new TaskNotification();
			taskNotification.setUserId(SessionHelper.getUserId(session));
			taskNotification.setTaskName("TESTINGTASKNOTIFICATION");
			taskNotification.setTaskInfo("VN123 - 100USD; VN344 - 210USD; BJ321 - 127USD");
			taskNotification.setTaskId("TESTINGTASKNOTIFICATION");
			taskNotification.setStatus(0);
			DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			Date date = new Date();
			taskNotification.setSaveTime(dateFormat.format(date));
			taskNotification.setIsRead(0);
			taskNotification = taskNotificationService.create(taskNotification);
			
			TaskNotificationDTO taskNotificationDTO = new TaskNotificationDTO(taskNotification);
			List<TaskNotificationDTO> taskNotificationDTOs = new ArrayList<>();
			taskNotificationDTOs.add(taskNotificationDTO);
			
			try {
				ObjectMapper makeJson = new ObjectMapper();
				testingNotification = makeJson.writeValueAsString(taskNotificationDTOs);
			} catch (Exception e) {
				LOGGER.error("Error when make Json",e);
			}
			
			LOGGER.info("Notification: " + testingNotification);
			BroadcasterFactory.getDefault().lookup(SessionHelper.getUserId(session)).broadcast("11"+testingNotification);
			return "demo/atmostphere";
		}

	@RequestMapping(value = { "/API" }, method = RequestMethod.GET)
	public @ResponseBody
	ModelAndView getJsonRoundTrip(

			@RequestParam(value = "departureAirportCode") String departureAirportCode,
			@RequestParam(value = "arrivalAirportCode") String arrivalAirportCode,
			@RequestParam(value = "tripType") String tripType,
			@RequestParam(value = "cabinClass") String cabinClass,
			@RequestParam(value = "outboundDate") String outboundDate,
			@RequestParam(value = "inboundDate", required = false) String inboundDate,
			@RequestParam(value = "numAdults", required = false) String numAdults,
			@RequestParam(value = "numChildren", required = false) String numChildren,
			@RequestParam(value = "numInfants", required = false) String numInfants,
			@RequestParam(value = "rangeValue", required = false) String rangeValue) {

		JsonData jsonData = null;
		try {
			if (inboundDate == null) {
				jsonData = jsonDataService.getData(departureAirportCode,
						arrivalAirportCode, tripType, cabinClass, outboundDate,
						numAdults, numChildren, numInfants, rangeValue);
			} else {
				jsonData = jsonDataService.getData(departureAirportCode,
						arrivalAirportCode, tripType, cabinClass, inboundDate,
						outboundDate, numAdults, numChildren, numInfants,
						rangeValue);
			}
			//String msg = jsonData.getJson();
		} catch (Exception e) {
			LOGGER.info("Can't get Jsondata: ", e);
			String sMessage = "";
			return new ModelAndView("demo/API", "error", sMessage);
		}
		return new ModelAndView("demo/API", "json", jsonData.getJson());
	}

	@RequestMapping(method = RequestMethod.GET, value = "/currency")
	public ModelAndView updateCurrency() throws ClientProtocolException, IOException
	{
		CheckUpdateCurrency detector=new CheckUpdateCurrency();
		detector.injectService(countryService);
		detector.run();
		return new ModelAndView("demo/demo");
	}
	
	@RequestMapping(method = RequestMethod.GET, value = "/search-auto")
	public ModelAndView searchAutomatic() {

		Thread t = new Thread() {
			public void run() {
				TaskPrepartion taskPrepartion = new TaskPrepartion();
				taskPrepartion.runManually(taskService, taskUserIdService,
						exchangeRateService, emailService, userService,
						taskNotificationService);
			}
		};
		t.start();

		return new ModelAndView("flight/search");
	}
	
}
